﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	SPJob.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.ComponentModel;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace Smart.Common.Jobs
{
	/// <summary>
	/// SP Job base
	/// </summary>
	[Localizable(false)]
	public class SPJob : SPJobDefinition
	{
		protected const string WebUrlProperty = "webUrl";

		/// <summary>
		/// SP Job base
		/// </summary>
		public SPJob()
		{
		}

		/// <summary>
		/// SP Job base
		/// </summary>
		public SPJob(string jobName, string jobTitle, SPSite site, SPWeb web)
			: base(jobName, site.WebApplication, null, SPJobLockType.Job)
		{
			if (jobName.IsNullOrEmpty() || jobTitle.IsNullOrEmpty() || web == null)
				throw new ArgumentNullException();

			Title = jobTitle;

			Properties.Add(WebUrlProperty, web.Url);
		}

		/// <summary>
		/// Code to execute
		/// </summary>
		protected virtual void ExecuteInternal()
		{
			SPServices.EventManager.FireEvent(Const.TimerJobs.Events.JobExecuting, this, SPH.GetWeb());
			SPServices.EventManager.FireEvent(Const.TimerJobs.Events.JobExecutingTempl + Name, this, SPH.GetWeb());
		}

		/// <summary>
		/// Executed by timer service
		/// </summary>
		public override void Execute(Guid targetInstanceId)
		{
			var webUrl = Properties[WebUrlProperty].SToStr();

			H.LT("> Executing SPJob: {0} on {1}", Name, webUrl);

			if (webUrl.IsNullOrEmpty())
			{
				H.LT("< SPJob: {0} failed, webUrl is not defined", GetType().Name);

				throw new ArgumentException("webUrl");
			}

			try
			{
				SPH.RunUnder(webUrl, ExecuteInternal);
			}
			catch (Exception x)
			{
				H.LX("SPJob.Execute", "Execute Name: " + Name, x);
			}

			H.LT("< Executed SPJob: {0} on {1}", Name, webUrl);
		}

		protected override bool HasAdditionalUpdateAccess()
		{
			return true;
		}

		/// <summary>
		/// Return default schedule
		/// </summary>
		public virtual SPSchedule DefaultShedule
		{
			get { return new SPDailySchedule { BeginHour = 1, EndHour = 2 }; }
		}

		/// <summary>
		/// Register job
		/// </summary>
		public virtual void Register(SPSchedule schedule)
		{
			Schedule = schedule ?? DefaultShedule;

			Update();
		}

		/// <summary>
		/// Unregister job
		/// </summary>
		public virtual void Unregister()
		{
			Delete();
		}

		/// <summary>
		/// Return full job name
		/// </summary>
		public static string GetFullJobName(string jobName, SPWeb web)
		{
			var site = web.Site;

			return String.Concat(jobName, "-", web.Name, "-", site.ID.GetHashCodeX(), web.ID.GetHashCodeX());
		}

		/// <summary>
		/// Register specified job
		/// </summary>
		public static void Register<TJobType>(string jobName, SPWeb web) where TJobType : SPJob
		{
			Register<TJobType>(jobName, web, null);
		}

		/// <summary>
		/// Register specified job
		/// </summary>
		public static void Register<TJobType>(string jobName, SPWeb web, SPSchedule schedule) where TJobType : SPJob
		{
			if (jobName == null) throw new ArgumentNullException("jobName");
			if (web == null) throw new ArgumentNullException("web");

			Unregister(jobName, web);

			try
			{
				var fullJobName = GetFullJobName(jobName, web);

				var job = (TJobType)Activator.CreateInstance(typeof(TJobType), fullJobName, web.Site, web);

				job.Register(schedule);
			}
			catch (Exception x)
			{
				H.LX("SPJob.Register", x);
			}
		}

		/// <summary>
		/// Unregister specified job
		/// </summary>
		public static void Unregister(string jobName, SPWeb web)
		{
			if (jobName == null) throw new ArgumentNullException("jobName");
			if (web == null) throw new ArgumentNullException("web");

			try
			{
				var fullJobName = GetFullJobName(jobName, web);

				foreach (var job in web.Site.WebApplication.JobDefinitions)
				{
					if (job.Name.EqIC(fullJobName))
					{
						((SPJob)job).Unregister();
					}
				}
			}
			catch (Exception x)
			{
				H.LX("SPJob.Unregister", x);
			}
		}
	}
}